package org.reborn.engine.system

import SystemMessage._

import org.reborn.utils.Logging
import org.apache.log4j.Logger
import scala.actors.Actor
import scala.actors.Actor._

/**
 * Manages and initiates updates for a set of dependent engine systems
 */
class SystemManager extends Actor with Logging{
	
	private var _systems = Set[System]()
	private lazy val _loopStart = new LoopStart(this)
	private lazy val _loopEnd = new LoopEnd(this)
	
	private var _shutdownSignal = false;
	
	private var _lastTime = 0L
	private var _startTime = 0L
	
	def noDependency = _loopStart

	def act(){
		loop{
			react{
				case LoopFinished =>{
					if(_shutdownSignal)
						_loopEnd ! ShutdownComplete(null)
					else
						startLoop()
				}
				case InitializationFinished =>{
					//All systems are set up, so start the loop
					startLoop()
				}
				case DeinitializationFinished =>{
					exit()
				}
			}
		}
	}
	
	private def startLoop(){
		val newTime = System.nanoTime() 
	
		//Calculate the elapsed time since the last frame
    	val dt = 
			if(_lastTime == 0) {
				_startTime = newTime
				0.0 
			}
			else{
				(newTime - _lastTime).asInstanceOf[Double] / 1000000000.0
			}

		//Send a message to the LoopStart system to kick off the loop
		_loopStart.resetLoop()
		_loopEnd.resetLoop()
		_systems.foreach(_.resetLoop())
		
		_loopStart ! UpdateComplete(dt, null)
	}
	
	final def elapsedTime():Double = {
		val newTime = System.nanoTime()
		
		(newTime - _startTime).asInstanceOf[Double] / 1000000000.0
	}
	
	def +=(sys:System):Unit = {
		log.info("Registering System " + sys + " with with the SystemManager.")
		_systems += (sys)
		for(reqSys <- sys.requiredSystems){
			if(!_systems.contains(reqSys)){
				log.info("Required (dependency) System " + reqSys + " was not registered with the SystemManager... ")
				this += reqSys
			}
		}
		for(reqSys <- sys.dependentSystems){
			if(!_systems.contains(reqSys)){
				log.info("Dependent (downstream dependency) System " + reqSys + " was not registered with the SystemManager... ")
				this += reqSys
			}
		}
	}
	
	private def detectedCyclicDependency(nextDep:System,depChain:List[System]):Boolean = {
		if(depChain.exists(_ == nextDep) || nextDep.requiredSystems.contains(nextDep)){
			return true
		}
		else{
			if(nextDep.requiredSystems.isEmpty){
				return false
			}
			else{
				val newDepChain = nextDep :: depChain
				return nextDep.requiredSystems.exists{(dep) =>
					detectedCyclicDependency(dep, newDepChain)
				}
			}
		}
	}
	
	def run(){
		_systems.foreach{sys =>
			_loopEnd.addRequiredSystem(sys)
			sys.addRequiredSystem(_loopStart)
		}
		if(detectedCyclicDependency(_loopEnd,List())){
			log.error("Cyclical dependency detected in System dependency heirarchy.")
			throw new IllegalStateException("Cyclical dependency detected in System dependency heirarchy.")
		}
		
		start()
		_loopStart.startSystem()
		_loopEnd.startSystem()
		_systems.foreach(_.startSystem())
		_loopStart ! SetupComplete(null)
	}
	
	def stop(){
		_shutdownSignal = true
	}
}
